using System;
using System.Collections.Specialized;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.ReportingServices.Interfaces;
using AUSRIS.Framework.Logging;
using System.Xml;
using System.Globalization;
using System.Collections;

namespace AUSRIS.Reports.Extensions.Security.Authorization
{
	public class AuthorizationExtension : IAuthorizationExtension
	{
		#region Private Fields

		private StringCollection adminUserNames;
		private ISecurityProvider securityProvider;

		private static Hashtable catalogOperationNameMap;
		private static Hashtable folderOperationNameMap;
		private static Hashtable modelItemOperationNameMap;
		private static Hashtable modelOperationNameMap;
		private static Hashtable reportOperationNameMap;
		private static Hashtable resourceOperationNameMap;
		private static Hashtable dataSourceOperationNameMap;

		#endregion

		#region Constructor(s)

		static AuthorizationExtension()
		{
			InitializeMaps();
		}

		public AuthorizationExtension()
		{
			this.adminUserNames = new StringCollection();
			this.securityProvider = ProviderFactory.GetProvider<ISecurityProvider>();
		}

		#endregion

		#region IAuthorizationExtension Members

		public bool CheckAccess(string userName, IntPtr userToken, byte[] secDesc, ModelItemOperation requiredOperation)
		{
			AceCollection acl = DeserializeAcl(secDesc);
			return CheckOperations(userName, acl, requiredOperation);
		}

		public bool CheckAccess(string userName, IntPtr userToken, byte[] secDesc, ModelOperation requiredOperation)
		{
			AceCollection acl = DeserializeAcl(secDesc);
			return CheckOperations(userName, acl, requiredOperation);
		}

		public bool CheckAccess(string userName, IntPtr userToken, byte[] secDesc, DatasourceOperation requiredOperation)
		{
			AceCollection acl = DeserializeAcl(secDesc);
			return CheckOperations(userName, acl, requiredOperation);
		}

		public bool CheckAccess(string userName, IntPtr userToken, byte[] secDesc, ResourceOperation[] requiredOperations)
		{
			bool canAccess = true;
			foreach ( CatalogOperation operation in requiredOperations )
			{
				if ( !CheckAccess(userName, userToken, secDesc, operation) )
				{
					canAccess = false;
					break;
				}
			}
			return canAccess;
		}

		public bool CheckAccess(string userName, IntPtr userToken, byte[] secDesc, ResourceOperation requiredOperation)
		{
			AceCollection acl = DeserializeAcl(secDesc);
			return CheckOperations(userName, acl, requiredOperation);
		}

		public bool CheckAccess(string userName, IntPtr userToken, byte[] secDesc, FolderOperation[] requiredOperations)
		{
			bool canAccess = true;
			foreach ( CatalogOperation operation in requiredOperations )
			{
				if ( !CheckAccess(userName, userToken, secDesc, operation) )
				{
					canAccess = false;
					break;
				}
			}
			return canAccess;
		}

		public bool CheckAccess(string userName, IntPtr userToken, byte[] secDesc, FolderOperation requiredOperation)
		{
			AceCollection acl = DeserializeAcl(secDesc);
			return CheckOperations(userName, acl, requiredOperation);
		}

		public bool CheckAccess(string userName, IntPtr userToken, byte[] secDesc, ReportOperation requiredOperation)
		{
			AceCollection acl = DeserializeAcl(secDesc);
			return CheckOperations(userName, acl, requiredOperation);
		}

		public bool CheckAccess(string userName, IntPtr userToken, byte[] secDesc, CatalogOperation[] requiredOperations)
		{
			bool canAccess = true;
			foreach ( CatalogOperation operation in requiredOperations )
			{
				if ( !CheckAccess(userName, userToken, secDesc, operation) )
				{
					canAccess = false;
					break;
				}
			}
			return canAccess;
		}

		public bool CheckAccess(string userName, IntPtr userToken, byte[] secDesc, CatalogOperation requiredOperation)
		{
			AceCollection acl = DeserializeAcl(secDesc);
			return CheckOperations(userName, acl, requiredOperation);
		}

		/// <summary>
		/// Returns a security descriptor that is stored with an individual 
		/// item in the report server database. 
		/// </summary>
		/// <param name="acl">
		/// The access code list (ACL) created by the report 
		/// server for the item. It contains a collection of access code entry 
		/// (ACE) structures.
		/// </param>
		/// <param name="itemType">
		/// The type of item for which the security descriptor is created.
		/// </param>
		/// <param name="stringSecDesc">
		/// Optional. A user-friendly description of the security descriptor, 
		/// used for debugging. This is not stored by the report server.
		/// </param>
		/// <returns>
		/// Should be implemented to return a serialized access code list for the item.
		/// </returns>
		public byte[] CreateSecurityDescriptor(AceCollection acl, SecurityItemType itemType, out string stringSecDesc)
		{
#if DEBUG
			Log.Debug(Log.GetSource(), "");
#endif
			// Creates a memory stream and serializes the ACL for storage.
			BinaryFormatter bf = new BinaryFormatter();
			using ( MemoryStream result = new MemoryStream() )
			{
				bf.Serialize(result, acl);
				stringSecDesc = null;
				return result.GetBuffer();
			}
		}

		/// <summary>
		/// Returns the set of permissions a specific user has for a specific 
		/// item managed in the report server database. This provides underlying 
		/// support for the Web service method GetPermissions().
		/// </summary>
		/// <param name="userName">
		/// The name of the user as returned by the GetUserInfo method.
		/// </param>
		/// <param name="userToken">
		/// Pointer to the user ID returned by GetUserInfo.
		/// </param>
		/// <param name="itemType">
		/// The type of item for which the permissions are returned.
		/// </param>
		/// <param name="secDesc">
		/// The security descriptor associated with the item.
		/// </param>
		/// <returns></returns>
		public StringCollection GetPermissions(string userName, IntPtr userToken, SecurityItemType itemType, byte[] secDesc)
		{
#if DEBUG
			Log.Debug(Log.GetSource(), "userName: {0}", userName);
#endif
			StringCollection permissions = new StringCollection();

			//if they are build in admin, include all permissions
			if ( this.adminUserNames.Contains(userName) )
			{
				this.AddAllPermissions(permissions);
			}
			else
			{
				// if not built-in admin, include all permissions defined for user for the item
				AceCollection acl = DeserializeAcl(secDesc);
				foreach ( AceStruct ace in acl )
				{
					if ( 0 == String.Compare(userName, ace.PrincipalName, true, CultureInfo.CurrentCulture) )
					{
						this.AddPermissionsFromAce(permissions, ace);
					}
				}

				//also add permissions for the user's roles
				string[] roles = this.securityProvider.ListRoles(userName);
				if ( roles != null )
				{
					foreach ( string role in roles )
					{
						foreach ( AceStruct ace in acl )
						{
							if ( 0 == String.Compare(role, ace.PrincipalName, true, CultureInfo.CurrentCulture) )
							{
								this.AddPermissionsFromAce(permissions, ace);
							}
						}
					}
				}
			}
			return permissions;
		}

		#endregion

		#region Private Methods

		private void AddPermissionsFromAce(StringCollection permissions, AceStruct ace)
		{
			foreach ( CatalogOperation aclOperation in ace.CatalogOperations )
			{
				if ( !permissions.Contains((string) catalogOperationNameMap[aclOperation]) )
				{
					permissions.Add((string) catalogOperationNameMap[aclOperation]);
				}
			}
			foreach ( ReportOperation aclOperation in ace.ReportOperations )
			{
				if ( !permissions.Contains((string) reportOperationNameMap[aclOperation]) )
				{
					permissions.Add((string) reportOperationNameMap[aclOperation]);
				}
			}
			foreach ( FolderOperation aclOperation in ace.FolderOperations )
			{
				if ( !permissions.Contains((string) folderOperationNameMap[aclOperation]) )
				{
					permissions.Add((string) folderOperationNameMap[aclOperation]);
				}
			}
			foreach ( ModelOperation aclOperation in ace.ModelOperations )
			{
				if ( !permissions.Contains((string) modelOperationNameMap[aclOperation]) )
				{
					permissions.Add((string) modelOperationNameMap[aclOperation]);
				}
			}
			foreach ( ModelItemOperation aclOperation in ace.ModelItemOperations )
			{
				if ( !permissions.Contains((string) modelItemOperationNameMap[aclOperation]) )
				{
					permissions.Add((string) modelItemOperationNameMap[aclOperation]);
				}
			}
			foreach ( ResourceOperation aclOperation in ace.ResourceOperations )
			{
				if ( !permissions.Contains((string) resourceOperationNameMap[aclOperation]) )
				{
					permissions.Add((string) resourceOperationNameMap[aclOperation]);
				}
			}
			foreach ( DatasourceOperation aclOperation in ace.DatasourceOperations )
			{
				if ( !permissions.Contains((string) dataSourceOperationNameMap[aclOperation]) )
				{
					permissions.Add((string) dataSourceOperationNameMap[aclOperation]);
				}
			}
		}

		private void AddAllPermissions(StringCollection permissions)
		{
			foreach ( CatalogOperation oper in catalogOperationNameMap.Keys )
			{
				if ( !permissions.Contains((string) catalogOperationNameMap[oper]) )
				{
					permissions.Add((string) catalogOperationNameMap[oper]);
				}
			}
			foreach ( ReportOperation oper in reportOperationNameMap.Keys )
			{
				if ( !permissions.Contains((string) reportOperationNameMap[oper]) )
				{
					permissions.Add((string) reportOperationNameMap[oper]);
				}
			}
			foreach ( FolderOperation oper in folderOperationNameMap.Keys )
			{
				if ( !permissions.Contains((string) folderOperationNameMap[oper]) )
				{
					permissions.Add((string) folderOperationNameMap[oper]);
				}
			}
			foreach ( ModelOperation oper in modelOperationNameMap.Keys )
			{
				if ( !permissions.Contains((string) modelOperationNameMap[oper]) )
				{
					permissions.Add((string) modelOperationNameMap[oper]);
				}
			}
			foreach ( ModelItemOperation oper in modelItemOperationNameMap.Keys )
			{
				if ( !permissions.Contains((string) modelItemOperationNameMap[oper]) )
				{
					permissions.Add((string) modelItemOperationNameMap[oper]);
				}
			}
			foreach ( ResourceOperation oper in resourceOperationNameMap.Keys )
			{
				if ( !permissions.Contains((string) resourceOperationNameMap[oper]) )
				{
					permissions.Add((string) resourceOperationNameMap[oper]);
				}
			}
			foreach ( DatasourceOperation oper in dataSourceOperationNameMap.Keys )
			{
				if ( !permissions.Contains((string) dataSourceOperationNameMap[oper]) )
				{
					permissions.Add((string) dataSourceOperationNameMap[oper]);
				}
			}
		}

		private bool CheckOperations(string principalName, AceCollection acl, object requiredOperation)
		{
#if DEBUG
			Log.Debug(Log.GetSource(), "principalName: {0}", principalName);
#endif
			if ( principalName.Trim() == String.Empty )
			{
				return false;
			}

			// prevent accidental lockout and grant a well-known admin login always rights
			if ( this.adminUserNames.Contains(principalName) )
			{
				return true;
			}

			// check if the individual login has been granted rights to perform the operation
			if ( IsPrincipalAuthorized(principalName, acl, requiredOperation) )
			{
				return true;
			}

			// check each role the user has
			string[] roles = this.securityProvider.ListRoles(principalName);
			if ( roles != null )
			{
				foreach ( string role in roles )
				{
					if ( IsPrincipalAuthorized(role, acl, requiredOperation) )
					{
						return true;
					}
				}
			}
			return false;
		}


		/// <summary>
		/// Used to deserialize the ACL that is stored by the report server.
		/// </summary>
		private AceCollection DeserializeAcl(byte[] secDesc)
		{
			AceCollection acl = new AceCollection();
			if ( secDesc != null )
			{
				BinaryFormatter bf = new BinaryFormatter();
				MemoryStream sdStream = new MemoryStream(secDesc);
				acl = (AceCollection) bf.Deserialize(sdStream);
			}
			return acl;
		}

		private bool IsPrincipalAuthorized(string principalName, AceCollection acl, object requiredOperation)
		{
#if DEBUG
			Log.Debug(Log.GetSource(), "principalName: {0}", principalName);
#endif
			CollectionBase operations = null;
			foreach ( AceStruct ace in acl )
			{
				if ( 0 != String.Compare(principalName, ace.PrincipalName, true, CultureInfo.CurrentCulture) )
				{
					continue;
				}
				if ( requiredOperation is CatalogOperation )
				{
					operations = ace.CatalogOperations;
				}
				else if ( requiredOperation is DatasourceOperation )
				{
					operations = ace.DatasourceOperations;
				}
				else if ( requiredOperation is FolderOperation )
				{
					operations = ace.FolderOperations;
				}
				else if ( requiredOperation is ModelItemOperation )
				{
					operations = ace.ModelItemOperations;
				}
				else if ( requiredOperation is ModelOperation )
				{
					operations = ace.ModelOperations;
				}
				else if ( requiredOperation is ReportOperation )
				{
					operations = ace.ReportOperations;
				}
				else if ( requiredOperation is ResourceOperation )
				{
					operations = ace.ResourceOperations;
				}

				if ( operations == null )
				{
					throw new Exception(string.Format("Required Operation {0} not supported in {1}", requiredOperation.GetType().Name, this.GetType().Name));
				}

				foreach ( object aclOperation in operations )
				{
					if ( aclOperation.ToString() == requiredOperation.ToString() )
					{
						return true;
					}
				}
			}
			return false;
		}

		/// <summary>
		/// Utility method used to create mappings to the various
		/// operations in Reporting Services. These mappings support
		/// the implementation of the GetPermissions method.
		/// </summary>
		private static void InitializeMaps()
		{
#if DEBUG
			Log.Debug(Log.GetSource(), "Initializing Maps");
#endif
			// create operation names data
			catalogOperationNameMap = new Hashtable();
			catalogOperationNameMap.Add(CatalogOperation.CreateRoles, OperationNames.OperCreateRoles);
			catalogOperationNameMap.Add(CatalogOperation.DeleteRoles, OperationNames.OperDeleteRoles);
			catalogOperationNameMap.Add(CatalogOperation.ReadRoleProperties, OperationNames.OperReadRoleProperties);
			catalogOperationNameMap.Add(CatalogOperation.UpdateRoleProperties, OperationNames.OperUpdateRoleProperties);
			catalogOperationNameMap.Add(CatalogOperation.ReadSystemProperties, OperationNames.OperReadSystemProperties);
			catalogOperationNameMap.Add(CatalogOperation.UpdateSystemProperties, OperationNames.OperUpdateSystemProperties);
			catalogOperationNameMap.Add(CatalogOperation.GenerateEvents, OperationNames.OperGenerateEvents);
			catalogOperationNameMap.Add(CatalogOperation.ReadSystemSecurityPolicy, OperationNames.OperReadSystemSecurityPolicy);
			catalogOperationNameMap.Add(CatalogOperation.UpdateSystemSecurityPolicy, OperationNames.OperUpdateSystemSecurityPolicy);
			catalogOperationNameMap.Add(CatalogOperation.CreateSchedules, OperationNames.OperCreateSchedules);
			catalogOperationNameMap.Add(CatalogOperation.DeleteSchedules, OperationNames.OperDeleteSchedules);
			catalogOperationNameMap.Add(CatalogOperation.ReadSchedules, OperationNames.OperReadSchedules);
			catalogOperationNameMap.Add(CatalogOperation.UpdateSchedules, OperationNames.OperUpdateSchedules);
			catalogOperationNameMap.Add(CatalogOperation.ListJobs, OperationNames.OperListJobs);
			catalogOperationNameMap.Add(CatalogOperation.CancelJobs, OperationNames.OperCancelJobs);
			catalogOperationNameMap.Add(CatalogOperation.ExecuteReportDefinition, OperationNames.ExecuteReportDefinition);

			if ( catalogOperationNameMap.Count != Enum.GetValues(typeof(CatalogOperation)).Length )
			{
				throw new Exception("Not all CatalogOperation values are mappeed to OperationNames");
			}

			folderOperationNameMap = new Hashtable();
			folderOperationNameMap.Add(FolderOperation.CreateFolder, OperationNames.OperCreateFolder);
			folderOperationNameMap.Add(FolderOperation.Delete, OperationNames.OperDelete);
			folderOperationNameMap.Add(FolderOperation.ReadProperties, OperationNames.OperReadProperties);
			folderOperationNameMap.Add(FolderOperation.UpdateProperties, OperationNames.OperUpdateProperties);
			folderOperationNameMap.Add(FolderOperation.CreateReport, OperationNames.OperCreateReport);
			folderOperationNameMap.Add(FolderOperation.CreateResource, OperationNames.OperCreateResource);
			folderOperationNameMap.Add(FolderOperation.ReadAuthorizationPolicy, OperationNames.OperReadAuthorizationPolicy);
			folderOperationNameMap.Add(FolderOperation.UpdateDeleteAuthorizationPolicy, OperationNames.OperUpdateDeleteAuthorizationPolicy);
			folderOperationNameMap.Add(FolderOperation.CreateDatasource, OperationNames.OperCreateDatasource);
			folderOperationNameMap.Add(FolderOperation.CreateModel, OperationNames.OperCreateModel);

			if ( folderOperationNameMap.Count != Enum.GetValues(typeof(FolderOperation)).Length )
			{
				throw new Exception("Not all FolderOperation values are mappeed to OperationNames");
			}

			modelItemOperationNameMap = new Hashtable();
			modelItemOperationNameMap.Add(ModelItemOperation.ReadProperties, OperationNames.OperReadProperties);

			if ( modelItemOperationNameMap.Count != Enum.GetValues(typeof(ModelItemOperation)).Length )
			{
				throw new Exception("Not all ModelItemOperation values are mappeed to OperationNames");
			}

			modelOperationNameMap = new Hashtable();
			modelOperationNameMap.Add(ModelOperation.Delete, OperationNames.OperDelete);
			modelOperationNameMap.Add(ModelOperation.ReadAuthorizationPolicy, OperationNames.OperReadAuthorizationPolicy);
			modelOperationNameMap.Add(ModelOperation.ReadContent, OperationNames.OperReadContent);
			modelOperationNameMap.Add(ModelOperation.ReadDatasource, OperationNames.OperReadDatasources);
			modelOperationNameMap.Add(ModelOperation.ReadModelItemAuthorizationPolicies, OperationNames.OperReadModelItemSecurityPolicies);
			modelOperationNameMap.Add(ModelOperation.ReadProperties, OperationNames.OperReadProperties);
			modelOperationNameMap.Add(ModelOperation.UpdateContent, OperationNames.OperUpdateContent);
			modelOperationNameMap.Add(ModelOperation.UpdateDatasource, OperationNames.OperUpdateDatasources);
			modelOperationNameMap.Add(ModelOperation.UpdateDeleteAuthorizationPolicy, OperationNames.OperUpdateDeleteAuthorizationPolicy);
			modelOperationNameMap.Add(ModelOperation.UpdateModelItemAuthorizationPolicies, OperationNames.OperUpdateModelItemSecurityPolicies);
			modelOperationNameMap.Add(ModelOperation.UpdateProperties, OperationNames.OperUpdateProperties);

			if ( modelOperationNameMap.Count != Enum.GetValues(typeof(ModelOperation)).Length )
			{
				throw new Exception("Not all ModelOperation values are mappeed to OperationNames");
			}

			reportOperationNameMap = new Hashtable();
			reportOperationNameMap.Add(ReportOperation.Delete, OperationNames.OperDelete);
			reportOperationNameMap.Add(ReportOperation.ReadProperties, OperationNames.OperReadProperties);
			reportOperationNameMap.Add(ReportOperation.UpdateProperties, OperationNames.OperUpdateProperties);
			reportOperationNameMap.Add(ReportOperation.UpdateParameters, OperationNames.OperUpdateParameters);
			reportOperationNameMap.Add(ReportOperation.ReadDatasource, OperationNames.OperReadDatasources);
			reportOperationNameMap.Add(ReportOperation.UpdateDatasource, OperationNames.OperUpdateDatasources);
			reportOperationNameMap.Add(ReportOperation.ReadReportDefinition, OperationNames.OperReadReportDefinition);
			reportOperationNameMap.Add(ReportOperation.UpdateReportDefinition, OperationNames.OperUpdateReportDefinition);
			reportOperationNameMap.Add(ReportOperation.CreateSubscription, OperationNames.OperCreateSubscription);
			reportOperationNameMap.Add(ReportOperation.DeleteSubscription, OperationNames.OperDeleteSubscription);
			reportOperationNameMap.Add(ReportOperation.ReadSubscription, OperationNames.OperReadSubscription);
			reportOperationNameMap.Add(ReportOperation.UpdateSubscription, OperationNames.OperUpdateSubscription);
			reportOperationNameMap.Add(ReportOperation.CreateAnySubscription, OperationNames.OperCreateAnySubscription);
			reportOperationNameMap.Add(ReportOperation.DeleteAnySubscription, OperationNames.OperDeleteAnySubscription);
			reportOperationNameMap.Add(ReportOperation.ReadAnySubscription, OperationNames.OperReadAnySubscription);
			reportOperationNameMap.Add(ReportOperation.UpdateAnySubscription, OperationNames.OperUpdateAnySubscription);
			reportOperationNameMap.Add(ReportOperation.UpdatePolicy, OperationNames.OperUpdatePolicy);
			reportOperationNameMap.Add(ReportOperation.ReadPolicy, OperationNames.OperReadPolicy);
			reportOperationNameMap.Add(ReportOperation.DeleteHistory, OperationNames.OperDeleteHistory);
			reportOperationNameMap.Add(ReportOperation.ListHistory, OperationNames.OperListHistory);
			reportOperationNameMap.Add(ReportOperation.ExecuteAndView, OperationNames.OperExecuteAndView);
			reportOperationNameMap.Add(ReportOperation.CreateResource, OperationNames.OperCreateResource);
			reportOperationNameMap.Add(ReportOperation.CreateSnapshot, OperationNames.OperCreateSnapshot);
			reportOperationNameMap.Add(ReportOperation.ReadAuthorizationPolicy, OperationNames.OperReadAuthorizationPolicy);
			reportOperationNameMap.Add(ReportOperation.UpdateDeleteAuthorizationPolicy, OperationNames.OperUpdateDeleteAuthorizationPolicy);
			reportOperationNameMap.Add(ReportOperation.Execute, OperationNames.OperExecute);
			reportOperationNameMap.Add(ReportOperation.CreateLink, OperationNames.OperCreateLink);

			if ( reportOperationNameMap.Count != Enum.GetValues(typeof(ReportOperation)).Length )
			{
				throw new Exception("Not all ReportOperation values are mappeed to OperationNames");
			}

			resourceOperationNameMap = new Hashtable();
			resourceOperationNameMap.Add(ResourceOperation.Delete, OperationNames.OperDelete);
			resourceOperationNameMap.Add(ResourceOperation.ReadProperties, OperationNames.OperReadProperties);
			resourceOperationNameMap.Add(ResourceOperation.UpdateProperties, OperationNames.OperUpdateProperties);
			resourceOperationNameMap.Add(ResourceOperation.ReadContent, OperationNames.OperReadContent);
			resourceOperationNameMap.Add(ResourceOperation.UpdateContent, OperationNames.OperUpdateContent);
			resourceOperationNameMap.Add(ResourceOperation.ReadAuthorizationPolicy, OperationNames.OperReadAuthorizationPolicy);
			resourceOperationNameMap.Add(ResourceOperation.UpdateDeleteAuthorizationPolicy, OperationNames.OperUpdateDeleteAuthorizationPolicy);

			if ( resourceOperationNameMap.Count != Enum.GetValues(typeof(ResourceOperation)).Length )
			{
				throw new Exception("Not all ResourceOperation values are mappeed to OperationNames");
			}

			dataSourceOperationNameMap = new Hashtable();
			dataSourceOperationNameMap.Add(DatasourceOperation.Delete, OperationNames.OperDelete);
			dataSourceOperationNameMap.Add(DatasourceOperation.ReadProperties, OperationNames.OperReadProperties);
			dataSourceOperationNameMap.Add(DatasourceOperation.UpdateProperties, OperationNames.OperUpdateProperties);
			dataSourceOperationNameMap.Add(DatasourceOperation.ReadContent, OperationNames.OperReadContent);
			dataSourceOperationNameMap.Add(DatasourceOperation.UpdateContent, OperationNames.OperUpdateContent);
			dataSourceOperationNameMap.Add(DatasourceOperation.ReadAuthorizationPolicy, OperationNames.OperReadAuthorizationPolicy);
			dataSourceOperationNameMap.Add(DatasourceOperation.UpdateDeleteAuthorizationPolicy, OperationNames.OperUpdateDeleteAuthorizationPolicy);

			if ( dataSourceOperationNameMap.Count != Enum.GetValues(typeof(DatasourceOperation)).Length )
			{
				throw new Exception("Not all DatasourceOperation values are mappeed to OperationNames");
			}
		}

		#endregion

		#region IExtension Members

		public string LocalizedName
		{
			get
			{
				return null;
			}
		}

		public void SetConfiguration(string configuration)
		{
#if DEBUG
			Log.Debug(Log.GetSource(), "configuration: {0}", configuration);
#endif
			// Retrieve admin user and password from the config settings and verify
			XmlDocument doc = new XmlDocument();
			doc.LoadXml(configuration);
			if ( doc.DocumentElement.Name == "AdminConfiguration" )
			{
				foreach ( XmlNode child in doc.DocumentElement.ChildNodes )
				{
					if ( child.Name == "UserName" )
					{
						this.adminUserNames.Add(child.InnerText);
					}
				}
			}
			else
			{
				throw new Exception("Root element is not \"AdminConfiguration\" in config data.");
			}
			// add the administrators from the security provider
			foreach ( string userName in this.securityProvider.ListAdministrators() )
			{
				if ( !this.adminUserNames.Contains(userName) )
				{
					this.adminUserNames.Add(userName);
				}
			}
			if ( this.adminUserNames.Count == 0 )
			{
				throw new Exception("No Admin user configured.");
			}
		}

		#endregion
	}
}